package com.stx.jeepay.payment.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.stx.jeepay.core.entity.IsvInfoEntity;
import com.stx.jeepay.core.entity.MchAppEntity;
import com.stx.jeepay.core.entity.MchInfoEntity;
import com.stx.jeepay.core.entity.PayInterfaceConfigEntity;
import com.stx.jeepay.core.enums.CS;
import com.stx.jeepay.core.model.params.IsvParams;
import com.stx.jeepay.core.model.params.IsvsubMchParams;
import com.stx.jeepay.core.model.params.NormalMchParams;
import com.stx.jeepay.core.model.params.alipay.AlipayIsvParams;
import com.stx.jeepay.core.model.params.alipay.AlipayNormalMchParams;
import com.stx.jeepay.core.model.params.pppay.PpPayNormalMchParams;
import com.stx.jeepay.core.model.params.wxpay.WxpayIsvParams;
import com.stx.jeepay.core.model.params.wxpay.WxpayNormalMchParams;
import com.stx.jeepay.core.service.*;
import com.stx.jeepay.core.service.impl.SysConfigServiceImpl;
import com.stx.jeepay.payment.model.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 商户/服务商 配置信息上下文服务
 */
@Slf4j
@Service
public class ConfigContextService {

    /**
     * <商户ID, 商户配置项>
     **/
    private static final Map<String, MchInfoConfigContext> mchInfoConfigContextMap = new ConcurrentHashMap<>();

    /**
     * <应用ID, 商户配置上下文>
     **/
    private static final Map<String, MchAppConfigContext> mchAppConfigContextMap = new ConcurrentHashMap<>();

    /**
     * <服务商号, 服务商配置上下文>
     **/
    private static final Map<String, IsvConfigContext> isvConfigContextMap = new ConcurrentHashMap<>();

    @Autowired
    private MchInfoService mchInfoService;

    @Autowired
    private MchAppService mchAppService;

    @Autowired
    private PayInterfaceConfigService payInterfaceConfigService;

    @Autowired
    private IsvInfoService isvInfoService;

    /**
     * 初始化 [ISV支付参数配置信息]
     **/
    public void initIsvConfigContext(String isvNo) {
        if (!isCache()) { // 当前系统不进行缓存
            return;
        }
        // 查询出所有商户的配置信息并更新
        List<String> mchNoList = new ArrayList<>();
        mchInfoService.list(new LambdaQueryWrapper<MchInfoEntity>()
                        .select(MchInfoEntity::getMchNo)
                        .eq(MchInfoEntity::getIsvNo, isvNo))
                .stream().forEach(i -> mchNoList.add(i.getMchNo()));

        // 查询出所有 所属当前服务商的所有应用集合
        List<String> mchAppIdList = new ArrayList<>();
        if (!mchNoList.isEmpty()) {
            mchAppService.list(new LambdaQueryWrapper<MchAppEntity>()
                            .select(MchAppEntity::getAppId)
                            .in(MchAppEntity::getMchNo, mchNoList))
                    .stream().forEach(i -> mchAppIdList.add(i.getAppId()));
        }

        IsvConfigContext isvConfigContext = new IsvConfigContext();
        IsvInfoEntity isvInfo = isvInfoService.getById(isvNo);
        if (isvInfo == null) {
            for (String appId : mchAppIdList) {
                //将更新已存在缓存的商户配置信息 （每个商户下存储的为同一个 服务商配置的对象指针）
                MchAppConfigContext mchAppConfigContext = mchAppConfigContextMap.get(appId);
                if (mchAppConfigContext != null) {
                    mchAppConfigContext.setIsvConfigContext(null);
                }
            }
            isvConfigContextMap.remove(isvNo); //服务商有商户不可删除， 此处不再更新商户下的配置信息
            return;
        }

        // 设置商户信息
        isvConfigContext.setIsvNo(isvInfo.getIsvNo());
        isvConfigContext.setIsvInfo(isvInfo);

        // 查询商户的所有支持的参数配置
        List<PayInterfaceConfigEntity> allConfigList = payInterfaceConfigService.list(new LambdaQueryWrapper<PayInterfaceConfigEntity>()
                .select(PayInterfaceConfigEntity::getIfCode, PayInterfaceConfigEntity::getIfParams)
                .eq(PayInterfaceConfigEntity::getState, CS.YES)
                .eq(PayInterfaceConfigEntity::getInfoType, CS.INFO_TYPE_ISV)
                .eq(PayInterfaceConfigEntity::getInfoId, isvNo));

        for (PayInterfaceConfigEntity payInterfaceConfig : allConfigList) {
            isvConfigContext.getIsvParamsMap().put(
                    payInterfaceConfig.getIfCode(),
                    IsvParams.factory(payInterfaceConfig.getIfCode(), payInterfaceConfig.getIfParams())
            );
        }

        // 防止alipay client
        AlipayIsvParams alipayParams =
                isvConfigContext.getIsvParamsByIfCode(CS.IF_CODE.ALIPAY, AlipayIsvParams.class);
        if (alipayParams != null) {
            isvConfigContext.setAlipayClientWrapper(AlipayClientWrapper.buildAlipayClientWrapper(alipayParams));
        }

        //防止 WxJAVAService
        WxpayIsvParams wxpayParams = isvConfigContext.getIsvParamsByIfCode(CS.IF_CODE.WXPAY, WxpayIsvParams.class);
        if (wxpayParams != null) {
            isvConfigContext.setWxServiceWrapper(WxServiceWrapper.buildWxServiceWrapper(wxpayParams));
        }

        isvConfigContextMap.put(isvNo, isvConfigContext);

        //  查询出所有商户的配置信息并更新
        for (String appId : mchAppIdList) {
            //  将更新已存在缓存的商户配置信息 （每个商户下存储的为同一个 服务商配置的对象指针）
            MchAppConfigContext mchAppConfigContext = mchAppConfigContextMap.get(appId);
            if (mchAppConfigContext != null) {
                mchAppConfigContext.setIsvConfigContext(isvConfigContext);
            }
        }
    }

    /**
     * 接收 [商户配置信息] 的消息
     **/
    public synchronized void initMchInfoConfigContext(String mchNo) {
        if (!isCache()) { // 当前系统不进行缓存
            return;
        }

        //商户主体信息
        MchInfoEntity mchInfo = mchInfoService.getById(mchNo);
        if (mchInfo == null) { // 查询不到商户主体， 可能已经删除
            MchInfoConfigContext mchInfoConfigContext = mchInfoConfigContextMap.get(mchNo);

            // 删除所有的商户应用
            if (mchInfoConfigContext != null) {
                mchInfoConfigContext.getAppMap().forEach((k, v) -> mchInfoConfigContextMap.remove(k));
            }
            mchInfoConfigContextMap.remove(mchNo);
            return;
        }

        MchInfoConfigContext mchInfoConfigContext = new MchInfoConfigContext();

        // 设置商户信息
        mchInfoConfigContext.setMcnNo(mchInfo.getMchNo());
        mchInfoConfigContext.setMchType(mchInfo.getType());
        mchInfoConfigContext.setMchInfo(mchInfo);
        mchAppService.list(new LambdaQueryWrapper<MchAppEntity>()
                        .eq(MchAppEntity::getMchNo, mchNo))
                .stream().forEach(mchApp -> {
                    //1. 更新商户内appId集合
                    mchInfoConfigContext.putMchApp(mchApp);
                    MchAppConfigContext mchAppConfigContext = mchAppConfigContextMap.get(mchApp.getAppId());
                    if (mchAppConfigContext != null) {
                        mchAppConfigContext.setMchApp(mchApp);
                        mchAppConfigContext.setMchNo(mchInfo.getMchNo());
                        mchAppConfigContext.setMchType(mchInfo.getType());
                        mchAppConfigContext.setMchInfo(mchInfo);
                    }
                });
        mchInfoConfigContextMap.put(mchNo, mchInfoConfigContext);
    }

    private boolean isCache() {
        return SysConfigServiceImpl.IS_USE_CACHE;
    }

    /**
     * 初始化 [商户应用支付参数配置信息]
     **/
    public synchronized void initMchAppConfigContext(String mchNo, String appId) {
        if (!isCache()) { // 当前系统不进行缓存
            return;
        }

        // 获取商户的配置信息
        MchInfoConfigContext mchInfoConfigContext = getMchInfoConfigContext(mchNo);
        if (mchInfoConfigContext == null) {
            // 商户信息不存在
            return;
        }

        // 查询商户应用信息主体
        MchAppEntity dbMchApp = mchAppService.getById(appId);

        //DB已经删除或不存在
        if (dbMchApp == null) {
            mchAppConfigContextMap.remove(appId);
            mchInfoConfigContext.getAppMap().remove(appId); //清除主体信息中的appId
            return;
        }

        // 商户应用mchNo 与参数不匹配
        if (!dbMchApp.getMchNo().equals(mchNo)) {
            return;
        }
        //更新商户信息主体中的商户应用
        mchInfoConfigContext.putMchApp(dbMchApp);

        //商户主体信息
        MchInfoEntity mchInfo = mchInfoConfigContext.getMchInfo();
        MchAppConfigContext mchAppConfigContext = new MchAppConfigContext();

        // 设置商户信息
        mchAppConfigContext.setAppId(appId);
        mchAppConfigContext.setMchNo(mchInfo.getMchNo());
        mchAppConfigContext.setMchType(mchInfo.getType());
        mchAppConfigContext.setMchInfo(mchInfo);
        mchAppConfigContext.setMchApp(dbMchApp);

        // 查询商户的所有支持的参数配置
        List<PayInterfaceConfigEntity> allConfigList = payInterfaceConfigService.list(new LambdaQueryWrapper<PayInterfaceConfigEntity>()
                .select(PayInterfaceConfigEntity::getIfCode, PayInterfaceConfigEntity::getIfParams)
                .eq(PayInterfaceConfigEntity::getState, CS.YES)
                .eq(PayInterfaceConfigEntity::getInfoType, CS.INFO_TYPE_MCH_APP)
                .eq(PayInterfaceConfigEntity::getInfoId, appId));

        // 普通商户
        if (mchInfo.getType() == CS.MCH_TYPE_NORMAL) {
            for (PayInterfaceConfigEntity payInterfaceConfig : allConfigList) {
                mchAppConfigContext.getNormalMchParamsMap().put(
                        payInterfaceConfig.getIfCode(),
                        NormalMchParams.factory(payInterfaceConfig.getIfCode(), payInterfaceConfig.getIfParams())
                );
            }

            //放置alipay client
            AlipayNormalMchParams alipayParams = mchAppConfigContext.getNormalMchParamsByIfCode(CS.IF_CODE.ALIPAY, AlipayNormalMchParams.class);
            if (alipayParams != null) {
                mchAppConfigContext.setAlipayClientWrapper(AlipayClientWrapper.buildAlipayClientWrapper(alipayParams));
            }

            //放置 wxJavaService
            WxpayNormalMchParams wxpayParams = mchAppConfigContext.getNormalMchParamsByIfCode(CS.IF_CODE.WXPAY, WxpayNormalMchParams.class);
            if (wxpayParams != null) {
                mchAppConfigContext.setWxServiceWrapper(WxServiceWrapper.buildWxServiceWrapper(wxpayParams));
            }

            //放置 paypal client
            PpPayNormalMchParams ppPayMchParams = mchAppConfigContext.getNormalMchParamsByIfCode(CS.IF_CODE.PPPAY, PpPayNormalMchParams.class);
            if (ppPayMchParams != null) {
                mchAppConfigContext.setPaypalWrapper(PaypalWrapper.buildPaypalWrapper(ppPayMchParams));
            }
        } else {
            //服务商模式商户
            for (PayInterfaceConfigEntity payInterfaceConfig : allConfigList) {
                mchAppConfigContext.getIsvsubMchParamsMap().put(
                        payInterfaceConfig.getIfCode(),
                        IsvsubMchParams.factory(payInterfaceConfig.getIfCode(), payInterfaceConfig.getIfParams())
                );
            }

            //放置 当前商户的 服务商信息
            mchAppConfigContext.setIsvConfigContext(getIsvConfigContext(mchInfo.getIsvNo()));
        }
        mchAppConfigContextMap.put(appId, mchAppConfigContext);
    }

    /**
     * 获取 [商户配置信息]
     **/
    public MchInfoConfigContext getMchInfoConfigContext(String mchNo) {
        MchInfoConfigContext mchInfoConfigContext = mchInfoConfigContextMap.get(mchNo);

        //无此数据， 需要初始化
        if (mchInfoConfigContext == null) {
            initMchInfoConfigContext(mchNo);
        }

        return mchInfoConfigContextMap.get(mchNo);
    }

    /**
     * 获取 [商户应用支付参数配置信息]
     **/
    public MchAppConfigContext getMchAppConfigContext(String mchNo, String mchAppId) {
        MchAppConfigContext mchAppConfigContext = mchAppConfigContextMap.get(mchAppId);

        //无此数据， 需要初始化
        if (mchAppConfigContext == null) {
            initMchAppConfigContext(mchNo, mchAppId);
        }
        return mchAppConfigContextMap.get(mchAppId);
    }

    /**
     * 获取 [ISV支付参数配置信息]
     **/
    public IsvConfigContext getIsvConfigContext(String isvNo) {
        IsvConfigContext isvConfigContext = isvConfigContextMap.get(isvNo);

        //无此数据， 需要初始化
        if (isvConfigContext == null) {
            initIsvConfigContext(isvNo);
        }

        return isvConfigContextMap.get(isvNo);
    }
}
